package com.myjpa.generate;

import lombok.Getter;
import lombok.Setter;

/**
 * @author: yaoll
 * @date: 2020-09-04
 * @verison: 1.0
 */
@Setter
@Getter
public class ServiceGenerator {

	private StringBuilder buff;

	public void generate(GenerateContext ctx) {

		buff = new StringBuilder();
		buff.append("package " + ctx.getPkg() + ".service;\n");
		buff.append("\n");
		buff.append("import com.fasterxml.jackson.databind.node.ObjectNode;").append("\n");
		buff.append("import com.querydsl.core.types.dsl.BooleanExpression;").append("\n");
		buff.append("import ").append(ctx.getCriteriaPackage()).append(".CriteriaUtils;\n");
		buff.append("import ").append(ctx.getCriteriaPackage()).append(".JacksonCriteria;\n");
		buff.append("import ").append(ctx.getResponsePackage()).append(".PagedResponse;\n");
		buff.append("import ").append(ctx.getResponsePackage()).append(".MapResponse;\n");
		buff.append("import javax.transaction.Transactional;").append("\n");
		buff.append("import org.springframework.stereotype.Service;").append("\n");
		if (ctx.isWithModel()) {
			buff.append("import java.util.stream.Collectors;\n");
			buff.append("import ").append(ctx.getPkg()).append(".model.").append(ctx.getModelClass()).append(";\n");
		}
		buff.append("import org.springframework.beans.factory.annotation.Autowired;").append("\n");
		buff.append("import " + ctx.getPkg() + ".entity.*;").append("\n");
		buff.append("import " + ctx.getPkg() + ".repository." + ctx.getRepositoryClass()).append(";\n");

		buff.append("").append("\n");
		buff.append("import java.util.Date;").append("\n");
		buff.append("import java.util.LinkedList;").append("\n");
		buff.append("import java.util.List;").append("\n");
		buff.append("import java.util.Optional;").append("\n");
		buff.append("").append("\n");

		buff.append("@Service").append("\n");
		buff.append("public class " + ctx.getServiceClass() + " {").append("\n");
		buff.append("").append("\n");
		buff.append("\t").append("@Autowired").append("\n");
		buff.append("\t").append("private ").append(ctx.getRepositoryClass()).append(" ").append(ctx.getRepoName()).append(";\n");
		buff.append("").append("\n");
		buff.append("\t").append("@Autowired").append("\n");
		buff.append("\t").append("private CriteriaUtils criteriaUtils;\n");
		buff.append("").append("\n");
		buff.append(parse(ctx));
		buff.append("").append("\n");
		buff.append(query(ctx));
		buff.append("").append("\n");
		buff.append(create(ctx));
		buff.append("").append("\n");
		buff.append(update(ctx));
		buff.append("").append("\n");
		buff.append(delete(ctx));
		buff.append("}").append("\n");
		buff.append("").append("\n");
	}

	private String parse(GenerateContext ctx) {
		String qc = "Q" + ctx.getEntityClass();
		StringBuilder buff = new StringBuilder();
		buff.append("\t").append("private List<BooleanExpression> parse(JacksonCriteria criteria) {").append("\n");
//		buff.append("\t\t").append(qc + " qt = " + qc + "." + ctx.getName() + ";").append("\n");
//		buff.append("\t\t").append("List<BooleanExpression> exps = new LinkedList<>();").append("\n");
//		buff.append("\t\t").append("ObjectNode object = criteria.getCriteria();").append("\n");
		buff.append("\t\t").append("// TODO").append("\n");
//		buff.append("\t\t").append("return exps;").append("\n");
		buff.append("\t\t").append("return null;").append("\n");
		buff.append("\t").append("}").append("\n");
		return buff.toString();
	}

	private String query(GenerateContext ctx) {
		StringBuilder buff = new StringBuilder();
		boolean withModel = ctx.isWithModel();
		if (withModel) {
			buff.append("\t").append("public PagedResponse<" + ctx.getModelClass() + "> query(JacksonCriteria criteria) {").append("\n");
			//return criteriaUtils.query(QOrder.order, null, criteria);
			String entityClass = ctx.getEntityClass();
			String qc = "Q" + entityClass + "." + ctx.getName();

			buff.append("\t\t").append("PagedResponse<" + ctx.getEntityClass() + "> resp = criteriaUtils.query(" + qc + ", this::parse, criteria);").append("\n");
			buff.append("\t\t").append("PagedResponse<" + ctx.getModelClass() + "> result = new PagedResponse<>();").append("\n");
			buff.append("\t\t").append("result.setCount(resp.getCount())").append(";\n");
			buff.append("\t\t").append("List<" + ctx.getEntityClass() + "> dataList = resp.getData()").append(";\n");
			buff.append("\t\t").append("if (dataList != null && dataList.size() > 0) {").append("\n");
			buff.append("\t\t\t").append("List<" + ctx.getModelClass() + "> collect = dataList.stream().map(entity -> {").append("\n");
			buff.append("\t\t\t\t").append(ctx.getModelClass() + " model = entity.toModel();").append("\n");
			buff.append("\t\t\t\t").append("return model;").append("\n");
			buff.append("\t\t\t").append("}).collect(Collectors.toList());").append("\n");
			buff.append("\t\t\t").append("result.setData(collect);").append("\n");
			buff.append("\t\t").append("}").append("\n");
			buff.append("\t\t").append("return result;").append("\n");
			buff.append("\t").append("}").append("\n");
		} else {

			buff.append("\t").append("public PagedResponse<" + ctx.getEntityClass() + "> query(JacksonCriteria criteria) {").append("\n");
			//return criteriaUtils.query(QOrder.order, null, criteria);
			String entityClass = ctx.getEntityClass();
			String qc = "Q" + entityClass + "." + ctx.getName();

			buff.append("\t\t").append("PagedResponse<" + ctx.getEntityClass() + "> resp = criteriaUtils.query(" + qc + ", this::parse, criteria);").append("\n");
			buff.append("\t\t").append("return resp;").append("\n");
			buff.append("\t").append("}").append("\n");
		}

		return buff.toString();
	}

	private String create(GenerateContext ctx) {
		boolean withModel = ctx.isWithModel();
		String target = withModel ? ctx.getModelClass() : ctx.getEntityClass();
		StringBuilder buff = new StringBuilder();
		buff.append("\t").append("@Transactional\n");
		buff.append("\t").append("public MapResponse create(" + target + " param) {").append("\n");
		buff.append("\t\t").append("MapResponse response = new MapResponse();").append("\n");
		buff.append("\t\t").append("// TODO").append("\n");
		if (withModel) {
			buff.append("\t\t").append(ctx.getEntityClass() + " entity = " + ctx.getEntityClass() + ".fromModel(param);").append("\n");
//			buff.append("\t\t").append("BeanUtils.copyProperties(param, entity);").append("\n");
			buff.append("\t\t").append(ctx.getRepoName() + ".save(entity);").append("\n");
			buff.append("\t\t").append("response.add(\"id\", entity.getId());").append("\n");
		} else {
			buff.append("\t\t").append(ctx.getRepoName() + ".save(param);").append("\n");
			buff.append("\t\t").append("response.add(\"id\", param.getId());").append("\n");
		}
		buff.append("\t\t").append("return response;").append("\n");
		buff.append("\t").append("}").append("\n");
		return buff.toString();
	}


	private String update(GenerateContext ctx) {
		boolean withModel = ctx.isWithModel();
		String target = withModel ? ctx.getModelClass() : ctx.getEntityClass();
		StringBuilder buff = new StringBuilder();
		buff.append("\t").append("@Transactional\n");
		buff.append("\t").append("public MapResponse update(" + target + " param) {").append("\n");
		buff.append("\t\t").append("MapResponse response = new MapResponse();").append("\n");
		buff.append("\t\t").append("// TODO").append("\n");
		if (withModel) {
			buff.append("\t\t").append(ctx.getEntityClass() + " entity = " + ctx.getEntityClass() + ".fromModel(param);").append("\n");
//			buff.append("\t\t").append("BeanUtils.copyProperties(param, entity);").append("\n");
			buff.append("\t\t").append(ctx.getRepoName() + ".save(entity);").append("\n");
			buff.append("\t\t").append("response.add(\"id\", entity.getId());").append("\n");
		} else {
			buff.append("\t\t").append(ctx.getRepoName() + ".save(param);").append("\n");
			buff.append("\t\t").append("response.add(\"id\", param.getId());").append("\n");
		}
		buff.append("\t\t").append("return response;").append("\n");
		buff.append("\t").append("}").append("\n");
		return buff.toString();
	}


	private String delete(GenerateContext ctx) {
		boolean withModel = ctx.isWithModel();
		String target = withModel ? ctx.getModelClass() : ctx.getEntityClass();
		StringBuilder buff = new StringBuilder();

		buff.append("\t").append("@Transactional\n");
		buff.append("\t").append("public MapResponse delete(" + target + " param) {").append("\n");
		buff.append("\t\t").append("MapResponse response = new MapResponse();").append("\n");
		buff.append("\t\t").append("// TODO").append("\n");
		buff.append("\t\t").append(ctx.getRepoName() + ".deleteById(param.getId());").append("\n");
		buff.append("\t\t").append("return response;").append("\n");
		buff.append("\t").append("}").append("\n");
		return buff.toString();
	}
}
